定期実行するLambdaが「起動しなかったこと」を検知するCloudWatch Alarmを作る
Lambdaを定期実行する仕組みをよく作ります。
- 1時間に1回起動する
- 1日に1回起動する
これらのLambdaが「起動しなかった場合」に通知が欲しくなったので、CloudWatch Alarmを作ってみました。
実際にLambdaが起動しない事象に遭遇したことは無いですが、このAlarmがあると、「ちゃんと起動しているよね?」というモヤモヤが解消されます。万が一に気づける保険ですね。
おすすめの方
- 定期実行するLambdaが「起動しなかった場合」のCloudWatch Alarmを作りたい方
定期実行するLambdaとCloudWatch Alarmを作成する
sam init
sam init \ --runtime python3.8 \ --name Lambda-No-Start-Alarm-Sample \ --app-template hello-world \ --package-type Zip
SAMテンプレート
CloudWatch Alarmは、Period(期間) * EvaluationPeriods(評価期間)
を1時間または1日にしています。
- 1時間に1回起動するLambda
- Period(期間): 5分
- EvaluationPeriods(評価期間): 12
- Statistic(統計): Sum
- 1日に1回起動するLambda
- Period(期間): 5分
- EvaluationPeriods(評価期間): 288
- Statistic(統計): Sum
これにより、次の条件を満たすとアラーム状態になります。
- 「12データポイント(12個*5分=60分) の Invocationsの合計」が1より小さい
- 「288データポイント(288個*5分=24時間) の Invocationsの合計」が1より小さい
Lambdaが起動しないことを確認したいので、「Invocationsメトリクスが無ければNG」です。 期間を5分から1分にすることも可能ですが、「Invocationsメトリクス」の到着が少し遅れるとすぐにアラーム状態になるため、余裕を見て5分にしています。 期間を60分にした場合も、「Invocationsメトリクス」の到着具合によってアラーム状態にならない可能性があります。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: Lambda-No-Start-Alarm-Sample Resources: HelloWorldFunction: Type: AWS::Serverless::Function Properties: CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.8 Timeout: 5 Events: HelloWorld: Type: Schedule Properties: Schedule: cron(0 */1 * * ? *) # 毎時0分に実行 Enabled: true HelloWorldFunctionLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub /aws/lambda/${HelloWorldFunction} HelloWorldFunction2: Type: AWS::Serverless::Function Properties: CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.8 Timeout: 5 Events: HelloWorld: Type: Schedule Properties: Schedule: cron(0 3 * * ? *) # 毎日12時に実行(JST) Enabled: true HelloWorldFunctionLogGroup2: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub /aws/lambda/${HelloWorldFunction2} HelloWorldFunctionInvocationsAlarm: Type: AWS::CloudWatch::Alarm Properties: Namespace: AWS/Lambda Dimensions: - Name: FunctionName Value: !Ref HelloWorldFunction MetricName: Invocations ComparisonOperator: LessThanThreshold Period: 300 EvaluationPeriods: 12 Statistic: Sum Threshold: 1 TreatMissingData: breaching # AlarmActions: # - !Ref any-sns-topic # OKActions: # - !Ref any-sns-topic HelloWorldFunction2InvocationsAlarm: Type: AWS::CloudWatch::Alarm Properties: Namespace: AWS/Lambda Dimensions: - Name: FunctionName Value: !Ref HelloWorldFunction2 MetricName: Invocations ComparisonOperator: LessThanThreshold Period: 300 EvaluationPeriods: 288 Statistic: Sum Threshold: 1 TreatMissingData: breaching # AlarmActions: # - !Ref any-sns-topic # OKActions: # - !Ref any-sns-topic
Lambdaコード
Lambdaが起動すればOKなので、何もしません。
def lambda_handler(event, context): pass
デプロイ
デプロイします。
sam build sam package \ --output-template-file packaged.yaml \ --s3-bucket cm-fujii.genki-deploy sam deploy \ --template-file packaged.yaml \ --stack-name Lambda-No-Start-Alarm-Sample-Stack \ --s3-bucket cm-fujii.genki-deploy \ --capabilities CAPABILITY_NAMED_IAM \ --no-fail-on-empty-changeset
デプロイ直後は過去に動いたLambdaが無いので、アラーム発生状態になります。落ち着くまでしばらく待ちます。
1時間に1回起動するLambdaのアラームを確認する
アラーム未発生を確認する
1時間ごとにLambdaが起動しているため、アラーム状態ではありません。
Lambdaの定期実行を無効化して、アラーム発生を確認する
CloudWatch Events(EventBridge)のルールを無効化します。 Lambdaが実行するはずの時刻をすぎると、アラーム状態になりました。
Lambdaの定期実行を有効にして、アラーム解除を確認する
CloudWatch CloudWatch Events(EventBridge)のルールを有効に戻し、Lambdaが動くまで待つと、アラーム状態が解除されました。
履歴の様子は下記です。
1日に1回起動するLambdaのアラームを確認する
アラーム未発生を確認する
1日ごとにLambdaが起動しているため、アラーム状態ではありません。
Lambdaの定期実行を無効化して、アラーム発生を確認する
CloudWatch Events(EventBridge)のルールを無効化します。 Lambdaが実行するはずの時刻をすぎると、アラーム状態になりました。
Lambdaの定期実行を有効にして、アラーム解除を確認する
CloudWatch Events(EventBridge)のルールを有効に戻し、Lambdaが動くまで待つと、アラーム状態が解除されました。
履歴の様子は下記です。
さいごに
定期実行するLambdaが「起動しない場合」のアラームを作ってみました。「ちゃんと起動しているよね?」というモヤモヤが解消されるので、意外と役に立つと思います。